#pragma once

#include <iostream>
#include <memory>
#include <sys/epoll.h>
#include "socket.hpp"

using namespace socket_net;
class epollServer
{
    const static int gnum = 64;

public:
    epollServer(uint16_t port) : _port(port), _ListenSock(make_unique<TcpSocket>()), _epfd(-1)
    {
        InetAddr addr("0", _port);
        _ListenSock->BuildListenSocket(addr);
        // 创建epoll模型
        _epfd = epoll_create(128);
        if (_epfd < 0)
        {
            Log(FATAL, "epoll create fail!");
            exit(5);
        }
        Log(DEBUG, "epoll create success!");

        // 3. 只有一个listensock, listen sock 关心的事件：读事件
        struct epoll_event ev;
        ev.events = EPOLLIN;
        ev.data.fd = _ListenSock->sockfd();
        epoll_ctl(_epfd, EPOLL_CTL_ADD, _ListenSock->sockfd(), &ev);
    }
    ~epollServer()
    {
        // 因为有_epfd
        //  epoll_ctl(_epfd,EPOLL_CTL_DEL,_ListenSock->sockfd(),&ev);
        _ListenSock->Close();
        if (_epfd > 0)
            close(_epfd);
    }
    void AcceptClient()
    {
        // 只关心读，而读有listensock和normalsock
        InetAddr clientaddr;
        int sockfd = _ListenSock->Acceptaddr(&clientaddr);
        if (sockfd < 0)
            return;
        Log(DEBUG, "Get new Link, sockfd: %d, client info %s:%d\n", sockfd, clientaddr.ip().c_str(), clientaddr.port());
       struct epoll_event ev;
       ev.events=EPOLLIN;
       ev.data.fd=sockfd;
       epoll_ctl(_epfd,EPOLL_CTL_ADD,sockfd,&ev);
        Log(DEBUG, "_listensock ready, accept done, epoll_ctl done, newfd is: %d\n", sockfd);
    }

    void ServerIO(int pos)
    {
        char buffer[1024];
        int sockfd = _revs[pos].data.fd;
        ssize_t n = ::recv(sockfd, buffer, sizeof(buffer) , 0);
        if (n > 0)
        {
            buffer[n] = 0;
            cout << "client say# " << buffer << endl;
            string echostring = "[server echo#] ";
            echostring += buffer;
            ::send( sockfd, echostring.c_str(), echostring.size(), 0);
        }
        else if (n == 0)
        {
            Log(DEBUG, "%d is closed", sockfd);
            epoll_ctl(_epfd,EPOLL_CTL_DEL,_ListenSock->sockfd(),nullptr);
            ::close(sockfd);
        }
        else
        {
            Log(DEBUG, "%d recv is error", sockfd);
            epoll_ctl(_epfd,EPOLL_CTL_DEL,_ListenSock->sockfd(),nullptr);
            ::close(sockfd);
        }
    }
    void HanderEvents(int num)
    {
        for (int i = 0; i < num; i++)
        {
            // 获取就绪事件和就绪fd
            uint32_t revents = _revs[i].events;
            int sockfd = _revs[i].data.fd;
            // 就绪读事件
            if (sockfd & EPOLLIN)
            {
                if (sockfd == _ListenSock->sockfd())
                {
                    AcceptClient();
                }
                else
                {
                    // 普通sockfd读事件
                    ServerIO(i);
                }
            }
        }
    }
    void loop()
    {
        int timeout = -1;
        while (true)
        {
            // listensocket 等待新连接到来，等价于对方给我发送数据！我们作为读事件同一处理
            // 新连接到来 等价于 读事件就绪！
            int n = epoll_wait(_epfd, _revs, gnum, timeout);
            switch (n)
            {
            case 0:
                Log(DEBUG, "epoll timeout.....");
                break;
            case -1:
                Log(DEBUG, "epoll wait fail...");
                break;
            default:
                Log(DEBUG, "epoll Event things happen!n: %d", n);
                HanderEvents(n);
                break;
            }
        }
    }

private:
    uint16_t _port;
    std::unique_ptr<Socket> _ListenSock;
    int _epfd;

    struct epoll_event _revs[gnum];
};